AUTOCONF	= autoconf
CC		= @CC@
CFLAGS		= -c @CFLAGS@ @DEFS@ -I../include -I../src
LD		= @CC@
LDFLAGS		= @LDFLAGS@
LIBS		= @LIBS@
V		= 0

GCLIB		= libxmp-gc.a

.c.o:
	@CMD='$(CC) -MMD $(CFLAGS) -o $*.o $<'; \
	if [ "$(V)" -gt 0 ]; then echo $$CMD; else echo CC $*.o ; fi; \
	eval $$CMD

#
# Tests
#
#
REPLAYERS	= mod ft2 st3 it

QUIRKS		= 

SMPLOADERS	= 8bit 16bit delta signal endian skip

DEPACKERS	= pp sqsh s404 mmcmp zip zip_filtered zip_store zip_zip64 \
		  arc_method2 arc_method3 arc_method4 arc_method8 arc_method9 \
		  arc_subdir_6 arc_subdir_spark spark arcfs arcfs_subdir \
		  gzip compress rar j2b lzx lzx_merge lzx_store bzip2 xz \
		  lha_l0_lzhuff1 lha_l0_lzhuff5 lha_l1_lzhuff5 \
		  lha_l1_lzhuff6 lha_l1_lzhuff7 lha_l2_lzhuff7 \
		  lha_l0_filtered lha_l1_filtered lha_l2_filtered \
		  vorbis vorbis_8bit \
		  it_sample_8bit it_sample_16bit

PROWIZARD	= zen fuchs starpack

EFFECTS		= 0_arpeggio 1_slide_up 2_slide_down \
		  4_vibrato a_volslide \
		  8_setpan \
		  c_volset \
		  e9_retrig ed_delay ef_invert_loop \
		  f_set_speed \
		  volslide track_volslide \
		  okt_arpeggio per_slide per_toneporta \
		  panbrello globalvol gvol_slide s3m_bpm it_bpm fine_vibrato \
		  it_panslide it_vcol_g it_break_to_row it_multi_retrig \
		  it_smooth_macro reverse line_jump \
		  pastnote_cut pastnote_off pastnote_fade \
		  set_nna_cut set_nna_cont set_nna_off set_nna_fade \
		  note_slide note_slide_retrig \
		  persistent_slide persistent_vslide persistent_vibrato \
		  it_g00_nosuck it_l00_nosuck it_fine_vol_row_delay \
		  far_slide far_toneporta far_retrig far_noteoffset \
		  far_vibrato far_vibrato_per far_volslide far_tempo \
		  med_retrig \
		  ult_tempo ult_toneporta

PATLOOPS	= st301 st321 st301_breakjump st321_breakjump \
		  it100 it104 it210 it100_breakjump it200_breakjump \
		  mpt_it mpt_xm mpt_s3m \
		  mpt_breakjump_it mpt_breakjump_xm mpt_breakjump_s3m \
		  imf imf_s3m imf_breakjump imf_breakjump_s3m \
		  ptm ptm_breakjump \
		  liq liq_s3m liq_no liq_breakjump liq_breakjump_no \
		  dt_mod dt dt19 dt_breakjump dt_breakjump_mod \
		  octalyser octalyser_breakjump

API		= get_format_list create_context free_context \
		  test_module load_module load_module_from_memory \
		  load_module_from_file load_module_from_callbacks \
		  test_module_from_file test_module_from_memory \
		  test_module_from_callbacks \
		  start_player play_buffer \
		  set_position next_position prev_position set_position_midfx \
		  set_row set_player stop_module restart_module seek_time \
		  channel_mute channel_vol inject_event scan_module \
		  set_tempo_factor set_instrument_path

API_SMIX	= smix_play_instrument smix_load_sample smix_play_sample \
		  smix_channel_pan

STORLEK		= 01_arpeggio_pitch_slide \
		  02_arpeggio_no_value \
		  03_compatible_gxx_off \
		  04_compatible_gxx_on \
		  05_gxx_fine_slides_memory \
		  06_volume_column_and_fine_slides \
		  07_note_cut_with_sample \
		  08_out_of_range_delays \
		  09_sample_change_no_note \
		  10_pattern_loop \
		  11_infinite_pattern_loop \
		  12_tremor \
		  13_tremor_with_old_effects \
		  14_pingpong_loop_and_sample_number \
		  15_retrigger \
		  16_global_volume \
		  17_pattern_row_delay \
		  18_sample_number_new_note \
		  19_random_waveform \
		  20_pan_swing_and_set_pan \
		  21_pitch_slide_limits \
		  22_zero_cut_and_delay \
		  23_portamento_with_no_note \
		  24_short_envelope_loops \
		  25_portamento_and_pitch_slide

OPENMPT_XM	= 3xxins \
		  3xx_no_old_samp \
		  3xx_no_old_samp_noft \
		  arpeggio \
		  arpeggioclamp_old \
		  arpslide_old \
		  delay1 \
		  delay2 \
		  delay3 \
		  delaycombination \
		  delaycut \
		  e90 \
		  envloops \
		  envoff \
		  envretrig \
		  finetune \
		  finevol_linkmem \
		  glissando \
		  key_off \
		  keyoff2 \
		  keyoff_instr \
		  notelimit \
		  notelimit2 \
		  noteoff \
		  noteoff2 \
		  noteofffade \
		  noteoffvolume \
		  offdelay \
		  offsetrange \
		  panmemory \
		  panmemory2 \
		  panoff \
		  panslidemem \
		  pathead \
		  patterndelays \
		  patterndelaysretrig \
		  patloop_break \
		  patloop_weird \
		  pickup \
		  porta_linkmem \
		  porta_linkmem_old \
		  porta_offset \
		  porta_pickup \
		  setenvpos \
		  toneportamentomemory \
		  tremolowaveforms \
		  tremor \
		  tremorinstr \
		  tremorrecover \
		  vibratowaveforms

OPENMPT_IT	= autovibrato_reset \
		  bidi_loops \
		  carrynna \
		  cut_carry \
		  emptyslot \
		  envloopescape \
		  envloops \
		  envofflength \
		  envreset \
		  extreme_filter_test_1 \
		  fade_porta \
		  filter_7f \
		  filterenvreset \
		  filter_nna \
		  filter_reset \
		  filter_reset_carry \
		  finevolcolslide \
		  flt_env_carry \
		  fltmacro \
		  freqreset_noins \
		  globalvol_invalid \
		  gxsmp \
		  gxsmp2 \
		  gxxtest \
		  ins_flt_porta_reset \
		  instrumentnumberchange \
		  linearslides \
		  macro_extended_param \
		  macro_lastnote \
		  multizxx \
		  nomap \
		  noteoff2 \
		  noteoff3 \
		  noteoffinstr \
		  off_porta \
		  off_porta_compatgxx \
		  panreset \
		  porta_offset \
		  portainsnum \
		  portainsnumcompat \
		  portajuststoppednote \
		  portareset \
		  portasample \
		  portasamplecompat \
		  randompan \
		  retrig \
		  retrig_short \
		  s77 \
		  s7xinsnum \
		  samplenumberchange \
		  scx \
		  smpinspansurround \
		  stoppedinstrswap \
		  susafterloop \
		  swaptest \
		  swing1 \
		  swing2 \
		  swing3 \
		  vol_env_carry \
		  volcolmemory \
		  volume_macro_letters \
		  wnoteoff \
		  zxxsecrets

OPENMPT_S3M	= amigalimits \
		  freqlimits \
		  parammemory \
		  patterndelaysretrig \
		  periodlimit \
		  portasmpchange

OPENMPT_MOD	= amigalimitsfinetune \
		  arpwraparound \
		  delaybreak \
		  finetune \
		  instrswapretrigger \
		  patternjump \
		  portasmpchange \
		  portaswappt \
		  portatarget \
		  ptinstrswap \
		  ptinstrvolume \
		  ptoffset \
		  ptstoppedswap \
		  ptswapempty \
		  ptswapnoloop \
		  vibratoreset

MIXER_FUNCS	= monoout_mono_8bit_ monoout_mono_16bit_ \
		  monoout_stereo_8bit_ monoout_stereo_16bit_ \
		  stereoout_mono_8bit_ stereoout_mono_16bit_ \
		  stereoout_stereo_8bit_ stereoout_stereo_16bit_

MIXER_FUNCS_ALL	= $(addsuffix nearest,${MIXER_FUNCS}) \
		  $(addsuffix linear,${MIXER_FUNCS}) \
		  $(addsuffix linear_filter,${MIXER_FUNCS}) \
		  $(addsuffix spline,${MIXER_FUNCS}) \
		  $(addsuffix spline_filter,${MIXER_FUNCS})

MIXER		= interpolation_default interpolation_loop bidi_sync \
		  ${MIXER_FUNCS_ALL} downmix_8bit downmix_16bit \
		  mpt116_preamp

READ		= file_32bit_little_endian file_32bit_big_endian \
		  file_24bit_little_endian file_24bit_big_endian \
		  file_16bit_little_endian file_16bit_big_endian \
		  file_8bit \
		  mem_32bit_little_endian mem_32bit_big_endian \
		  mem_16bit_little_endian mem_16bit_big_endian \
		  mem_hio mem_hio_nosize file_hio_pipe

WRITE		= file_32bit_little_endian file_32bit_big_endian \
		  file_16bit_little_endian file_16bit_big_endian \
		  file_8bit

PLAYER		= read_event scan loop period_amiga period_mod_range pan \
		  med_extsample med_hold med_instruments med_ss2defpitch \
		  med_synth med_synth_2 med_compat_tempo \
		  hmn_extras \
		  note_off_ft2 note_off_it \
		  virtual_channel nna_cut nna_cont nna_off nna_fade dct_note \
		  s3m_sample_porta \
		  it_channel_filter it_cut_invalid_ins \
		  it_fade_env_reset it_fade_env_reset_carry \
		  it_keyoff it_note_after_cut it_note_delay_nna it_sample_porta \
		  it_sus_after_loop_bidi it_default_volume \
		  it_duplicate_check_transpose it_portamento_nna_sample \
		  it_portamento_offset it_portamento_sustain \
		  it_portamento_after_keyoff it_portamento_after_keyoff_cg \
		  it_portamento_after_cut_fade it_portamento_after_cut_fade_cg \
		  it_portamento_envelope_reset it_portamento_envelope_reset_cg \
		  xm_portamento_envelope_reset xm_portamento_target \
		  xm_keyoff_with_instrument \
		  xm_envelope_zero_loop xm_envelope_set_pos \
		  ft2_note_noins_after_keyoff \
		  ft2_note_noins_after_invalid_ins \
		  invalid_period invalid_mod_length invalid_mod_channels \
		  it_noteoff_nosuck mdl_period mtm_tempo sample_sync

LOADER		= 6chn mod_adpcm4 mod_noterange mod_noterange2 mod_scrm mod_notawow \
		  mod_invalid mod_tdz3 mod_dt mod_svdmf \
		  nst \
		  ust \
		  wow wow_extra \
		  m15 m15_invalid m15_invalid2 m15_invalid3 m15_invalid4 \
		  m15_invalid5 m15_invalid6 m15_orderquirk m15_short_rip \
		  s3m s3m_adpcm s3m_schism s3m_stereo \
		  xm102 xm_adpcm xm_xmlite xm_short xm_instsamples xm_pattrunc \
		  xm_stereo xm_stereo_vorbis\
		  it it_adpcm it_oldins it_schism it_invalid_fx it_stereo \
		  669 \
		  abk \
		  arch \
		  asylum \
		  chiptracker \
		  coco coco_patalign \
		  dbm dbm_rows dbm_penv dbm_venv \
		  digi \
		  dsmi dsmi_08 dsmi_09 dsmi_10 dsmi_10_trunc dsmi_11 dsmi_13 \
		  dsmi_track0 dsmi_note7f dsmi_pan dsmi_vol \
		  dtm dtm_2015 dtm_203 dtm_19 \
		  emod \
		  far far_fx \
		  flt flt8 \
		  fnk \
		  gdm gdm_fx gdm_fx2 \
		  hmn \
		  ice \
		  imf \
		  ims \
		  j2b \
		  liq liq_100 liq_no liq_no_fx \
		  masi \
		  masi16 \
		  mdl0 mdl \
		  med2 med3 med3_song med4 med4_decvol med4_song \
		  mmd0 mmd0_compattempo mmd1_longpat mmd_iff3oct mmdc \
		  mmd3 mmd3_stereo \
		  mfp \
		  mgt \
		  mtm \
		  okt \
		  ptm \
		  pt36 \
		  rtm \
		  sfx \
		  stim \
		  stm stm_blankpat stm_v1 \
		  stx \
		  sym sym_4096pat sym_fx sym_lzwquirk \
		  ult \
		  xmf \
		  ac1d \
		  crb crb2 \
		  di \
		  eureka \
		  fc_m \
		  fuchs \
		  fuzzac \
		  gmc \
		  hrt \
		  ksm \
		  mp_noid \
		  novotrade \
		  np1 np2 np3 \
		  nru \
		  p40a p40b p41a p50a p60 p61 \
		  pha pha_short \
		  pm10 pm18 \
		  pp10_1 pp10_2 pp10_3 pp10_4 \
		  pp21_1 pp21_2 \
		  pp30_1 pp30_2 \
		  pru1 pru2 \
		  skyt \
		  starpack \
		  tdd \
		  titanics \
		  tp1 tp2 tp3 \
		  unic unic_id0 unic2 \
		  wn \
		  xann

PROBLEMATIC	= length_data_jack \
		  length_condom_corruption \
		  length_klisje_paa_klisje \
		  length_killvictor \
		  length_nebulos \
		  length_roadblast \
		  length_ode2ptk \
		  length_flowerpower \
		  length_space_traveller \
		  length_listen \
		  length_dammed_illusion \

FUZZER		= misc \
		  mod_no_null_terminator \
		  mod_no_valid_orders \
		  mod_scan_row_limit \
		  st_invalid_sample_count \
		  st_truncated \
		  s3m_invalid_sample_size \
		  s3m_invalid_sample_size2 \
		  xm_invalid \
		  xm_orders_mismatch \
		  xm_vorbis_crash \
		  xm_vorbis_leak \
		  xm_vorbis_truncated \
		  xm_zero_samples \
		  it_dca_3 \
		  it_invalid_compressed \
		  it_long_patterns \
		  it_truncated \
		  669_truncated \
		  abk_0_instruments \
		  abk_test_title \
		  abk_truncated \
		  amf_truncated \
		  amf_truncated2 \
		  arch_duplicate_chunk \
		  arch_invalid \
		  asy_invalid_samples \
		  chip_truncated \
		  coco_invalid_sequence \
		  dbm_bad_fx_conv \
		  dbm_chunk_order \
		  dbm_invalid_instruments \
		  dbm_name_buffer_overflow \
		  dbm_sample_count \
		  dbm_truncated \
		  digi_truncated \
		  dt_duplicate_chunk \
		  dt_invalid \
		  dt_truncated \
		  emod_duplicate_chunk \
		  far_truncated \
		  flt_umr \
		  fnk_channels_bound \
		  fnk_invalid_sample_size \
		  fnk_patterns_bound \
		  fnk_truncated \
		  gal4_duplicate_instrument \
		  gal4_env_point_bound \
		  gal4_invalid_sample_num \
		  gal4_truncated \
		  gal5_channels_bound \
		  gal5_duplicate_instrument \
		  gal5_invalid_sample_num \
		  gal5_truncated \
		  gal5_truncated_info \
		  gdm_invalid_sample_size \
		  gdm_samples_bound \
		  gdm_truncated \
		  gdm_truncated_header \
		  hmn_truncated \
		  ice_truncated \
		  imf_truncated \
		  ims_scan_loop \
		  ims_truncated_magic \
		  liq_no_valid_orders \
		  liq_truncated \
		  masi_invalid_length \
		  masi_seek_loop \
		  masi_truncated \
		  masi16_invalid \
		  mdl_duplicate_chunk \
		  mdl_duplicate_is_chunk \
		  mdl_duplicate_pa_chunk \
		  mdl_duplicate_sa_chunk \
		  mdl_ii_after_is \
		  mdl_invalid_chunk_order \
		  mdl_invalid_run \
		  mdl_invalid_sample \
		  mdl_truncated \
		  mdl_umr \
		  med2_truncated \
		  med3_invalid_pattern \
		  med4_instrument_name \
		  med4_invalid_iff \
		  med4_invalid_sample \
		  mfp_truncated \
		  mgt_invalid \
		  mgt_patterns_bound \
		  mmd0_sample_count \
		  mmd1_channel_count \
		  mmd1_invalid \
		  mmd3_invalid \
		  mmd3_invalid_mmdinfo \
		  mmd3_invalid_sample_size \
		  mtm_channels_bound \
		  okt_duplicate_chunk \
		  okt_invalid_chunk_order \
		  okt_sbod_leak \
		  pt3_ptdt_leak \
		  pt3_truncated \
		  ptm_truncated \
		  rtm_truncated \
		  rtm_zero_samples \
		  sfx_truncated \
		  stim_truncated \
		  stm_patterns_bound \
		  stx_instruments_bound \
		  stx_truncated \
		  sym_bad_sigmadelta \
		  sym_truncated \
		  sym_truncated_lzw \
		  ult_channels_bound \
		  ult_invalid_sample \
		  ult_invalid_tracks \
		  ult_truncated \
		  ult_v000 \
		  umx_invalid \
		  prowizard_ac1d_invalid \
		  prowizard_di_invalid \
		  prowizard_di_truncated \
		  prowizard_eureka_truncated \
		  prowizard_fuchs_invalid \
		  prowizard_heatseek_128_patterns \
		  prowizard_heatseek_truncated \
		  prowizard_ksm_truncated \
		  prowizard_noiserun_invalid \
		  prowizard_noiserun_truncated \
		  prowizard_novotrade_invalid \
		  prowizard_np2_invalid \
		  prowizard_np3_invalid \
		  prowizard_p40_invalid \
		  prowizard_p50_127_patterns \
		  prowizard_p50_truncated \
		  prowizard_p61a_invalid \
		  prowizard_p61a_truncated \
		  prowizard_pha_invalid \
		  prowizard_pm10c_invalid \
		  prowizard_pm10c_zero_length \
		  prowizard_pm18a_invalid \
		  prowizard_pm18a_zero_length \
		  prowizard_pp10_invalid \
		  prowizard_pp21_truncated \
		  prowizard_pp30_invalid \
		  prowizard_starpack_invalid \
		  prowizard_starpack_truncated \
		  prowizard_theplayer_invalid \
		  prowizard_titanics_truncated \
		  prowizard_tp1_invalid \
		  prowizard_tp3_invalid \
		  prowizard_unic_truncated \
		  prowizard_xann_invalid \
		  prowizard_zen_invalid \
		  depack_arc_invalid \
		  depack_arc_pak10 \
		  depack_arc_slow_rle \
		  depack_arcfs_invalid \
		  depack_bz2_invalid \
		  depack_bz2_truncated \
		  depack_compress_invalid \
		  depack_gz_invalid \
		  depack_lha_invalid \
		  depack_lha_truncated \
		  depack_lzx_invalid \
		  depack_muse_truncated \
		  depack_pp20_invalid \
		  depack_s404_invalid \
		  depack_sqsh_invalid \
		  depack_sqsh_truncated \
		  depack_zip_truncated \
		  play_mod_bad_invloop \
		  play_s3m_low_period_vibrato \
		  play_xm_bad_env_sustain \
		  play_xm_bad_instrument \
		  play_xm_vol_env_clamp \
		  play_it_adpcm_bound \
		  play_it_bad_env \
		  play_it_bad_loop \
		  play_it_bad_set_nna \
		  play_it_bad_sustain \
		  play_it_extreme_filter \
		  play_it_globalvol_marker \
		  play_it_interpolation_loop \
		  play_it_offset_reverse \
		  play_it_row_0_loop_row_delay \
		  play_it_sustain_bidi \
		  play_it_truncated \
		  play_it_vol_clamp \
		  play_669_low_freq \
		  play_abk_0_length_track \
		  play_asylum_bad_effects \
		  play_dbm_inst_no_samples \
		  play_far_highbpm \
		  play_gdm_bad_loop \
		  play_hmn_bad_loop_index \
		  play_hmn_bad_megaarp \
		  play_mdl_high_c5spd \
		  play_mdl_zero_samples \
		  play_med4_0_chn_invalid_ord \
		  play_med4_hybrid_0_waveforms \
		  play_mmd1_synth_bad_tables \
		  play_rtm_autovib \
		  play_stm_bad_note_toneporta \

SYNTH		= #adlib #spectrum

CASE1_TESTS	= $(addprefix new_note_no_ins_,$(REPLAYERS)) \
		  $(addprefix new_note_same_ins_,$(REPLAYERS)) \
		  $(addprefix new_note_valid_ins_,$(REPLAYERS)) \
		  $(addprefix new_note_invalid_ins_,$(REPLAYERS))

CASE2_TESTS	= $(addprefix no_note_same_ins_,$(REPLAYERS)) \
		  $(addprefix no_note_valid_ins_,$(REPLAYERS)) \
		  $(addprefix no_note_invalid_ins_,$(REPLAYERS))

CASE3_TESTS	= $(addprefix porta_no_ins_,$(REPLAYERS)) \
		  $(addprefix porta_same_ins_,$(REPLAYERS)) \
		  $(addprefix porta_valid_ins_,$(REPLAYERS)) \
		  $(addprefix porta_invalid_ins_,$(REPLAYERS))

QUIRK_TESTS	= $(addprefix quirk_,$(QUIRKS)) \
		  $(addprefix no_quirk_,$(QUIRKS))

SMPLOAD_TESTS	= $(addprefix sample_load_,$(SMPLOADERS))

DEPACK_TESTS	= $(addprefix depack_,$(DEPACKERS))

PROWIZARD_TESTS	= $(addprefix prowizard_,$(PROWIZARD))

EFFECT_TESTS	= $(addprefix effect_,$(EFFECTS))
PATLOOP_TESTS	= $(addprefix effect_pattern_loop_,$(PATLOOPS))

SEQUENCER_TESTS	= prev_order_start prev_order_skip prev_order_start_seq \
		  next_order_skip

STORLEK_TESTS	= $(addprefix storlek_,$(STORLEK))

OPENMPT_XM_TESTS= $(addprefix openmpt_xm_,$(OPENMPT_XM))

OPENMPT_IT_TESTS= $(addprefix openmpt_it_,$(OPENMPT_IT))

OPENMPT_S3M_TESTS= $(addprefix openmpt_s3m_,$(OPENMPT_S3M))

OPENMPT_MOD_TESTS= $(addprefix openmpt_mod_,$(OPENMPT_MOD))

MIXER_TESTS	= $(addprefix mixer_,$(MIXER))

READ_TESTS	= $(addprefix read_,$(READ))

WRITE_TESTS	= $(addprefix write_,$(WRITE))

PLAYER_TESTS	= $(addprefix player_,$(PLAYER))

LOADER_TESTS	= $(addprefix loader_,$(LOADER))

SYNTH_TESTS	= $(addprefix synth_,$(SYNTH))

API_TESTS	= $(addprefix api_,$(API)) $(addprefix api_,$(API_SMIX))

FUZZER_TESTS	= $(addprefix fuzzer_,$(FUZZER))

PROBLEM_TESTS	= $(addprefix module_,$(PROBLEMATIC))

TESTS		= $(READ_TESTS) \
		  $(WRITE_TESTS) \
		  $(SMPLOAD_TESTS) \
		  $(DEPACK_TESTS) \
		  $(PROWIZARD_TESTS) \
		  string_adjustment \
		  $(LOADER_TESTS) \
		  $(API_TESTS) \
		  $(QUIRK_TESTS) \
		  $(CASE1_TESTS) \
		  $(CASE2_TESTS) \
		  $(CASE3_TESTS) \
		  $(NNA_TESTS) \
		  $(EFFECT_TESTS) \
		  $(PATLOOP_TESTS) \
		  $(SEQUENCER_TESTS) \
		  $(STORLEK_TESTS) \
		  $(OPENMPT_XM_TESTS) \
		  $(OPENMPT_IT_TESTS) \
		  $(OPENMPT_S3M_TESTS) \
		  $(OPENMPT_MOD_TESTS) \
		  $(PLAYER_TESTS) \
		  $(MIXER_TESTS) \
		  $(SYNTH_TESTS) \
		  $(FUZZER_TESTS) \
		  $(PROBLEM_TESTS)

TEST_NAMES	= $(addprefix test_,$(TESTS))

MAIN_OBJS	= util.o main.o simple_module.o compare_mixer_data.o
TEST_OBJS	= $(MAIN_OBJS) $(TEST_NAMES:=.o)

TEST_DFILES	= Makefile $(TEST_OBJS:.o=.c) test.h md5.h data

TEST_PATH	= .
SRC_PATH	= ../src

TEST_INTERNAL	= md5.o win32.o hio.o load_helpers.o loaders/itsex.o dataio.o scan.o \
		  loaders/sample.o loaders/common.o filetype.o period.o memio.o \
		  depackers/xfnmatch.o far_extras.o flow.o lfo.o rng.o

T_OBJS 		= $(addprefix $(TEST_PATH)/,$(TEST_OBJS)) \
		  $(addprefix $(SRC_PATH)/,$(TEST_INTERNAL))

GCT_OBJS 	= $(addprefix $(TEST_PATH)/,$(TEST_OBJS))

default-test: check

dist-test:
	mkdir -p $(DIST)/$(TEST_PATH)
	cp -RPp $(addprefix $(TEST_PATH)/,$(TEST_DFILES)) $(DIST)/$(TEST_PATH)

clean: fuzzerclean
	@rm -f core *~ $(T_OBJS)
	@rm -f *.o
	@rm -f *.d

distclean: clean
	@rm -f config.log config.status Makefile all_tests.c libxmp-tests* .test .read_test write_test

vc-prepare: $(TEST_PATH)/all_tests.txt
	@echo Generate Makefile.vc
	@sed -e 's!@MAINSRCS@!\\\r\n $(subst /,\\,$(MAIN_OBJS:.o=.c \\\r\n))!' \
	     -e 's!@XMPSRCS@!\\\r\n $(subst .o,.c \\\r\n,$(subst /,\\,$(addprefix $(SRC_PATH)/,$(TEST_INTERNAL))))!' \
	     Makefile.vc.in > Makefile.vc

sinclude $(T_OBJS:.o=.d)

#
# Utilities
#

utilities: gen_mixer_data gen_module_data xmpchk

gen_mixer_data: gen_mixer_data.o
	@CMD='$(LD) $(LDFLAGS) -o $@ gen_mixer_data.o -L../lib -lxmp'; \
	if [ "$(V)" -gt 0 ]; then echo $$CMD; else echo LD $@ ; fi; \
	eval $$CMD

gen_module_data: gen_module_data.o util.o ${SRC_PATH}/hio.o ${SRC_PATH}/dataio.o ${SRC_PATH}/memio.o ${SRC_PATH}/md5.o
	@CMD='$(LD) $(LDFLAGS) -o $@ $^ -L../lib -lxmp $(LIBS)'; \
	if [ "$(V)" -gt 0 ]; then echo $$CMD; else echo LD $@ ; fi; \
	eval $$CMD

xmpchk: libxmp_fuzz.o ${SRC_PATH}/rng.o ${SRC_PATH}/loaders/vorbis.o
	@CMD='$(LD) $(LDFLAGS) -o $@ $^ -L../lib -lxmp $(LIBS)'; \
	if [ "$(V)" -gt 0 ]; then echo $$CMD; else echo LD $@ ; fi; \
	eval $$CMD

#
# Run standard tests
#

check: $(TEST_PATH)/all_tests.c $(TEST_PATH)/all_tests.txt $(TEST_PATH)/libxmp-tests
	cd $(TEST_PATH); LD_LIBRARY_PATH=../lib DYLD_LIBRARY_PATH=../lib LIBRARY_PATH=../lib:$$LIBRARY_PATH PATH=$$PATH:../lib ./libxmp-tests

$(TEST_PATH)/libxmp-tests: $(T_OBJS)
	@CMD='$(LD) $(LDFLAGS) -o $@ $(T_OBJS) $(LIBS) -L../lib -lxmp'; \
	if [ "$(V)" -gt 0 ]; then echo $$CMD; else echo LD $@ ; fi; \
	eval $$CMD

#
# Run coverage test
#

covercheck: coverclean $(TEST_PATH)/all_tests.c $(TEST_PATH)/libxmp-covertest
	cd $(TEST_PATH); LD_LIBRARY_PATH=../lib DYLD_LIBRARY_PATH=../lib LIBRARY_PATH=../lib:$$LIBRARY_PATH ./libxmp-covertest ||:
	lcov -c -b .. -d .. -k src -k ../include --rc lcov_branch_coverage=1 -o libxmp.cov
	rm -Rf coverage
	genhtml -o coverage --rc lcov_branch_coverage=1 libxmp.cov

coverclean:
	@rm -f $(GCOBJS) ../lib/$(GCLIB)

$(TEST_PATH)/libxmp-covertest: $(GCT_OBJS) ../lib/$(GCLIB)
	@CMD='$(LD) $(LDFLAGS) -o $@ $(GCT_OBJS) ../lib/$(GCLIB) -lgcov $(LIBS)'; \
	if [ "$(V)" -gt 0 ]; then echo $$CMD; else echo LD $@ ; fi; \
	eval $$CMD

../lib/$(GCLIB):
	make -C .. coverage

$(TEST_PATH)/main.o: $(TEST_PATH)/main.c $(TEST_PATH)/all_tests.c $(TEST_PATH)/test.h $(TEST_PATH)/all_tests.c

$(TEST_PATH)/test.h $(TEST_PATH)/main.c: $(TEST_PATH)/all_tests.c
$(addprefix $(TEST_PATH)/,$(TEST_OBJS)): $(TEST_PATH)/all_tests.c

$(TEST_PATH)/all_tests.c: $(TEST_PATH)/Makefile
	@echo > $@; \
	for i in $(TEST_NAMES); do \
		echo "declare_test($$i);" >> $@; \
	done

$(TEST_PATH)/all_tests.txt: $(TEST_PATH)/Makefile
	@$(RM) $@; \
	for i in $(TEST_NAMES); do \
		echo "$$i" >> $@; \
	done

$(addprefix $(SRC_PATH)/,$(TEST_INTERNAL)): $(SRC_PATH)/player.h

#
# Fuzzers
#

FUZZLIB_PATH		= .fuzzer
FUZZ_CFLAGS		+= -fno-omit-frame-pointer -g -DLIBXMP_LIBFUZZER -I../include -I../src
FUZZ_LDFLAGS		+= -fuse-ld=lld -L$(FUZZLIB_PATH)
FUZZ_CC			?= clang

FUZZ_ASAN_FLAGS		= -O3 -fsanitize=fuzzer,address,undefined \
			  -fno-sanitize-recover=all -fno-sanitize=shift-base
FUZZ_HWASAN_FLAGS	= -O3 -fsanitize=fuzzer,hwaddress,undefined \
			  -fno-sanitize-recover=all -fno-sanitize=shift-base
FUZZ_MSAN_FLAGS		= -O3 -fsanitize=fuzzer,memory -fsanitize-memory-track-origins=2

FUZZ_ASAN_FLAGS		+= $(FUZZ_CFLAGS)
FUZZ_HWASAN_FLAGS	+= $(FUZZ_CFLAGS)
FUZZ_MSAN_FLAGS		+= $(FUZZ_CFLAGS)

FUZZLIB_ASAN_FLAGS	= $(subst fuzzer,fuzzer-no-link,$(FUZZ_ASAN_FLAGS))
FUZZLIB_HWASAN_FLAGS	= $(subst fuzzer,fuzzer-no-link,$(FUZZ_HWASAN_FLAGS))
FUZZLIB_MSAN_FLAGS	= $(subst fuzzer,fuzzer-no-link,$(FUZZ_MSAN_FLAGS))

FUZZ_MAKE		= CC=$(FUZZ_CC) \
			  cmake ../../../CMakeLists.txt -B. -S../../.. \
			  -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED=OFF && \
			  $(MAKE)

.PHONY: fuzzers fuzzerclean $(FUZZLIB_PATH)

fuzzers: libxmp_fuzz_asan libxmp_fuzz_msan

# This will build on x86_64 but currently is usable on ARM only.
ifneq ($(filter aarch64 arm64,$(shell uname -m)),)
fuzzers: libxmp_fuzz_hwasan
endif

fuzzerclean:
	rm -rf $(FUZZLIB_PATH) libxmp_fuzz_asan libxmp_fuzz_hwasan libxmp_fuzz_msan

$(FUZZLIB_PATH):
	rm -rf $(FUZZLIB_PATH)
	mkdir -p $(FUZZLIB_PATH)/asan $(FUZZLIB_PATH)/hwasan $(FUZZLIB_PATH)/msan

$(FUZZLIB_PATH)/libxmp-asan.a: $(FUZZLIB_PATH)
	(cd $(FUZZLIB_PATH)/asan && \
		CFLAGS="$(FUZZLIB_ASAN_FLAGS)" \
		LDFLAGS="$(FUZZLIB_ASAN_FLAGS)" \
		$(FUZZ_MAKE) && \
		mv libxmp.a ../libxmp-asan.a && \
		$(MAKE) clean)

$(FUZZLIB_PATH)/libxmp-hwasan.a: $(FUZZLIB_PATH)
	(cd $(FUZZLIB_PATH)/hwasan && \
		CFLAGS="$(FUZZLIB_HWASAN_FLAGS)" \
		LDFLAGS="$(FUZZLIB_HWASAN_FLAGS)" \
		$(FUZZ_MAKE) && \
		mv libxmp.a ../libxmp-hwasan.a && \
		$(MAKE) clean)

$(FUZZLIB_PATH)/libxmp-msan.a: $(FUZZLIB_PATH)
	(cd $(FUZZLIB_PATH)/msan && \
		CFLAGS="$(FUZZLIB_MSAN_FLAGS)" \
		LDFLAGS="$(FUZZLIB_MSAN_FLAGS)" \
		$(FUZZ_MAKE) && \
		mv libxmp.a ../libxmp-msan.a && \
		$(MAKE) clean)

libxmp_fuzz_asan: libxmp_fuzz.c $(FUZZLIB_PATH)/libxmp-asan.a
	@CMD='$(FUZZ_CC) $(FUZZ_ASAN_FLAGS) -o $@ $< $(FUZZ_LDFLAGS) -lxmp-asan'; \
	if [ "$(V)" -gt 0 ]; then echo $$CMD; else echo LD $@ ; fi; \
	eval $$CMD

libxmp_fuzz_hwasan: libxmp_fuzz.c $(FUZZLIB_PATH)/libxmp-hwasan.a
	@CMD='$(FUZZ_CC) $(FUZZ_HWASAN_FLAGS) -o $@ $< $(FUZZ_LDFLAGS) -lxmp-hwasan'; \
	if [ "$(V)" -gt 0 ]; then echo $$CMD; else echo LD $@ ; fi; \
	eval $$CMD

libxmp_fuzz_msan: libxmp_fuzz.c $(FUZZLIB_PATH)/libxmp-msan.a
	@CMD='$(FUZZ_CC) $(FUZZ_MSAN_FLAGS) -o $@ $< $(FUZZ_LDFLAGS) -lxmp-msan'; \
	if [ "$(V)" -gt 0 ]; then echo $$CMD; else echo LD $@ ; fi; \
	eval $$CMD
